home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Games of Daze
/
Infomagic - Games of Daze (Summer 1995) (Disc 1 of 2).iso
/
x2ftp
/
msdos
/
libs
/
graphsrc
/
g32.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-07-07
|
30KB
|
829 lines
/*
g3 - three dimensional graphics interface
history...
24 Mar 90 Added function prototypes
29 Oct 87 Scaling marker symbols by the pen diameter.
28 Oct 87 In polymarker_*_*, drawing n markers rather than
n-1. In polymarker_rel_2, saving current position
and using marker_abs_2 rather than marker_rel_2.
16 Jun 87 For a wide line, displacing pen by pen_diameter on
each pass. If pen_diameter is greater than 1, a
stroke is added across each end to square it off.
16 May 87 Hid debugging code behind #ifdef's.
Corrected aspect ratio scaling of marker symbols.
5 May 87 Using hardware for wide lines, if available.
24 Apr 86 If not widening, clipping first. Using hardware for
dashed lines, if available.
19 Apr 86 Not displaying empty labels.
2 Dec 85 Using new gotoxy() call sequence.
6 May 85 Added rudimentary text().
27 Apr 85 Not using iline(). changed from maybe_dashed, etc. to
after_line, etc. so line routines could be executed in any order required.
18 Apr 85 different line widths and styles implemented.
7 Apr 85 Added linewidth and linestyle stubs.
9 Mar 85 hid (*erase_line)() references behind #ifdef's. changed
init() references to init_graphics(), removed inquire_current_color().
15 Feb 85 iwline() installed - draws wide lines.
*/
#include <stdio.h>
#include <math.h>
#ifdef __TURBOC__
#include <ctype.h>
#endif
#include "g.h"
#include "g3.h"
#ifdef DEBUG
int textymin=400;
int textymax=-400;
#endif
/* integer line drawing routines */
static int
icline(int a1, int a2, int b1, int b2),
idline(int a1, int a2, int b1, int b2),
iwline(int a1, int a2, int b1, int b2);
static int clip( double *a, double *b, double *c );
int (*after_line)(int a1, int a2, int b1, int b2);
/* pointer to the line routine to follow line_abs_3() */
/* variables */
extern int debugging;
static int
/* pointer to the line routine to follow icline() */
(*after_clip)(int a1, int a2, int b1, int b2),
/* pointer to the line routine to follow iwline() */
(*after_wide)(int a1, int a2, int b1, int b2),
/* pointer to the line routine to follow idline() */
(*after_dashed)(int a1, int a2, int b1, int b2),
aspect, /* 10*pixel height/pixel width */
current_linewidth, /* width of line (units of pixel height) */
current_linestyle=SOLID, /* style of line */
current_x, current_y, /* current position (integer) */
marker_symbol=1, /* current marker symbol */
scaled=0, /* nonzero after markers have been rescaled */
#define MAX_STYLE 9
#define DASHES 8
styles[MAX_STYLE*DASHES]={ /* 0 - solid */
5,8,5,8,5,8,5,8, /* 1 - dashed */
5,3,5,3,5,3,5,3, /* 2 - short dashes */
4,1,4,1,4,1,4,1, /* 3 - dotted */
4,8,4,1,4,8,4,1, /* 4 - dash-dot */
4,9,4,1,4,1,0,0, /* 5 - dash-dot-dot */
4,10,4,1,4,1,4,1, /* 6 - dash-dot-dot-dot */
4,10,4,10,4,1,0,0, /* 7 - dash-dash-dot */
4,10,4,10,4,1,4,1, /* 8 - dash-dash-dot-dot */
10,15,10,15,10,15}, /* 9 - dashed */
style_array[DASHES],/* array of currently used dash lengths
in units of 1/8 pixel width */
style_index=0, /* index into style_array[] */
step=12, /* amount of current dash not yet drawn */
using_dash_hardware=0, /* nonzero if linestyles implemented in
hardware and we can use them (not widening) */
reversed=0; /* nonzero if endpoints of line have
been swapped by icline() */
extern int
clipping, /* nonzero if clipping is enabled */
front_clipping, /* nonzero if front clipping is enabled */
back_clipping, /* nonzero if back clipping is enabled */
graphics_level, /* level of CORE graphics requested */
initialized, /* nonzero after output driver is initialized */
need_depth, /* nonzero if depth must be calculated (perspective
projection or depth clipping) */
num_segments, /* number of segments that still exist */
persp_proj, /* nonzero if perspective projection requested */
segment_open, /* nonzero if a segment is open */
wmin1,wmax1, /* minimum & maximum x values in device coordinates */
wmin2,wmax2; /* minimum & maximum y values in device coordinates */
extern double
aspect_ratio, /* height/width ratio of display */
left_handed, /* 1 for LH world coordinate system, -1 for RH */
vdist, /* distance from viewpoint along view plane normal to
viewplane */
c_bottom[4],c_top[4], /* clip vectors...if x is visible, then */
c_left[4],c_right[4], /* x[0]*c[0] + x[1]*c[1] + x[2]*c[2] > c[3] */
c_near[4],c_far[4], /* for c equal to each of these six arrays */
/* cur_x, cur_y, cur_z, current position (world coordinates) (in g3.h) */
uu, vv, nn, /* current position (viewport coordinates) */
norm1, norm2, norm3, /* view plane normal */
p1, p2, p3, /* direction for parallel projection, or
center of projection */
up1, up2, up3, /* view up vector */
vrp1, vrp2, vrp3, /* view reference point */
umin, umax, /* window in world coordinates */
vmin, vmax,
wmin, wmax,
vp_xmin, vp_xmax, /* requested viewport in NDC */
vp_ymin, vp_ymax,
vp_zmin, vp_zmax,
ndc_width, ndc_height, ndc_depth, /* requested limits on NDC values */
rot11, rot12, rot13, rot14, /* rotation & projection matrix */
rot21, rot22, rot23, rot24,
rot31, rot32, rot33, rot34; /* (3rd row is for perspective projections) */
/* CORE graphics routines */
double charwidth, charheight;
double dx_plane, dy_plane, dz_plane;
double dx_charup, dy_charup, dz_charup;
int charpath, charjust, charprecision;
double charspace=0.;
/* inquire character attributes */
inquire_charsize(cw,ch) double *cw,*ch; /**/
{*cw=charwidth; *ch=charheight;
}
inquire_charplane(dx,dy,dz) double *dx,*dy,*dz; /**/
{*dx=dx_plane; *dy=dy_plane; *dz=dz_plane;
}
inquire_charup_2(dx,dy) double *dx,*dy; /**/
{*dx=dx_charup; *dy=dy_charup;
}
inquire_charup_3(dx,dy,dz) double *dx,*dy,*dz; /**/
{*dx=dx_charup; *dy=dy_charup; *dz=dz_charup;
}
double inquire_charspace() {return charspace;} /**/
int inquire_charpath() {return charpath;} /**/
int inquire_charjust() {return charjust;} /**/
int inquire_charprecision() {return charprecision;} /**/
/* inquire_current_position - report current position */
inquire_current_position_2(x,y) double *x,*y; {*x=cur_x; *y=cur_y;} /**/
inquire_current_position_3(x,y,z) double *x,*y,*z; /**/
{*x=cur_x; *y=cur_y; *z=cur_z;
}
/* inquire line parameters */
inquire_linestyle(n) int *n; {return (*n=current_linestyle);} /**/
inquire_linewidth(n) int *n; {return (*n=current_linewidth);} /**/
inquire_marker_symbol(n) int *n; {return (*n=marker_symbol);} /**/
/* inquire viewing parameters */
inquire_ndc_space_2(w,h) double *w,*h; /**/
{ *w=ndc_width; *h=ndc_height;
}
inquire_ndc_space_3(w,h,d) double *w,*h,*d; /**/
{ *w=ndc_width; *h=ndc_height; *d=ndc_depth;
}
inquire_viewport_2(xmin,xmax,ymin,ymax) /**/
double *xmin,*xmax,*ymin,*ymax;
{ *xmin=vp_xmin; *xmax=vp_xmax;
*ymin=vp_ymin; *ymax=vp_ymax;
}
inquire_viewport_3(xmin,xmax,ymin,ymax,zmin,zmax) /**/
double *xmin,*xmax,*ymin,*ymax,*zmin,*zmax;
{ *xmin=vp_xmin; *xmax=vp_xmax;
*ymin=vp_ymin; *ymax=vp_ymax;
*zmin=vp_zmin; *zmax=vp_zmax;
}
inquire_window(x1,x2,y1,y2) double *x1,*x2,*y1,*y2; /**/
{ *x1=umin; *x2=umax; *y1=vmin; *y2=vmax;}
inquire_open_temporary_segment() {return segment_open;} /**/
/* line - draw line from current position */
line_abs_3(x,y,z) double x,y,z; /**/
{ static int previous_x,previous_y;
static double a[3],b[3];
#ifdef TRACE
{
FILE *dfile;
dfile = fopen("dfile","a");
fprintf(dfile, "file %s line %3d: line_abs_3(%f,%f,%f)\n", __FILE__, __LINE__, x, y, z);
fclose(dfile);
}
#endif /* TRACE */
reversed=0;
a[0]=uu; a[1]=vv; a[2]=nn; previous_x=current_x; previous_y=current_y;
move_abs_3(x,y,z);
b[0]=uu; b[1]=vv; b[2]=nn;
if(persp_proj)
{
#ifdef DEBUG
/*if(debugging)
{printf("line (%10f,%10f,%10f) to (%10f,%10f,%10f) \n",
a[0],a[1],a[2],b[0],b[1],b[2]);
} */
#endif
if(front_clipping)
{if(clip(a,b,c_near)) return;
}
if(back_clipping)
{if(clip(a,b,c_far)) return;
}
else if((a[2]>0.)&&(b[2]>0.)) {} /* can use integer clipping */
else if(clipping)
{/* clip along four planes */
if(clip(a,b,c_left)||clip(a,b,c_right )||
clip(a,b,c_top )||clip(a,b,c_bottom) ) return;
if((a[2]<=0.)||(b[2]<=0.))return;
}
else return; /* one end invisible, clipping forbidden - omit line */
(*after_line)((int)(a[0]/a[2]),(int)(a[1]/a[2]),
(int)(b[0]/b[2]),(int)(b[1]/b[2]));
}
else /* parallel projection */
{if(front_clipping||back_clipping)
{if((front_clipping&&clip(a,b,c_near))||
(back_clipping&&clip(a,b,c_far))) return;
(*after_line)((int)a[0],(int)a[1],(int)b[0],(int)b[1]);
}
else (*after_line)(previous_x,previous_y,current_x,current_y);
}
}
/* marker - display marker "n" */
static int
mark_index[]={0,1,3, 6,12,14, 19,24,28,32};
static int xm[]=
/* x1 y1 x2 y2 ...for each line segment */
{00,00,00,00, /* dot */
00,-20,00,20, -40,00,40,00, /* plus */
-20,-18,20,18, -20,18,20,-18, -40,00,40,00, /* asterisk */
-20,18,20,18, 20,18,40,00, 40,00,20,-18, /* hexagon */
20,-18,-20,-18, -20,-18,-40,00, -40,00,-20,18,
-36,-18,36,18, 36,-18,-36,18, /* cross */
-36,0,-36,18, -36,18,36,18, /* square */
36,18,36,-18, 36,-18,-36,-18, -36,-18,-36,0,
20,-10,40,00, 40,00,00,20, /* diamond */
00,20,-40,00, -40,00,00,-20, 00,-20,20,-10,
00,-20,-40,-20, -40,-20,00,20, /* triangle, point up */
00,20,40,-20, 40,-20,00,-20,
00,20,-40,20, -40,20,00,-20, /* triangle, point down */
00,-20,40,20, 40,20,00,20
};
#define MAX_MARKER_SYMBOL 9
marker_abs_3(x,y,z) double x,y,z; /**/
{ int i, j, resetting;
move_abs_3(x,y,z);
if(front_clipping) {if(nn<=wmin) return;}
if(back_clipping) {if(nn>wmax) return;}
if(persp_proj)
{if(nn<=0.) return;
current_x=(int)(uu/nn); current_y=(int)(vv/nn);
}
if(clipping)
{if((current_x<wmin1)||(current_x>wmax1)||
(current_y<wmin2)||(current_y>wmax2) ) return;
}
j=mark_index[marker_symbol]*4;
/*
gotoxy(0,char_height); printf("x,y=%d,%d",current_x,current_y);
gotoxy(0,2*char_height);
i=mark_index[marker_symbol-1];
printf("xm[%d...%d]=%d",i,j,xm[i]);
for(i++ ;i<j; i++) printf(", %d",xm[i]);
gotoxy(0,3*char_height);
i=mark_index[marker_symbol-1];
printf("ym[%d...%d]=%d",i,j,ym[i]);
for(i++ ;i<j; i++) printf(", %d",ym[i]);
*/
resetting=0;
if(new_linestyle &&
current_linestyle!=SOLID &&
(current_linewidth==1 || new_linewidth))
{resetting=1;
(*new_linestyle)(SOLID);
}
for (i=mark_index[marker_symbol-1]*4; i<j; i+=4)
{(*draw_line)(current_x+xm[i], current_y+xm[i+1],
current_x+xm[i+2],current_y+xm[i+3]);
if(resetting) reset_line();
/* printf("\n*(draw_line)(%d,%d, %d,%d)",x1,y1,x2,y2); */
}
}
/* move - move from current position */
move_abs_3(x,y,z) double x,y,z; /**/
{ cur_x=x; cur_y=y; cur_z=z;
uu=rot11*x + rot12*y + rot13*z + rot14;
vv=rot21*x + rot22*y + rot23*z + rot24;
if(need_depth) {nn=rot31*x + rot32*y + rot33*z + rot34;}
if(!persp_proj) {current_x=(int)uu; current_y=(int)vv;}
}
/* ndc_space - define limits on normalized device coordinate values
w > h allows use of display device that's wider than it
is high. (w and h in range 0. to 1., either w or h must be 1.) */
ndc_space_2(w,h) double w,h; {ndc_space_3(w,h,1.);} /**/
ndc_space_3(w,h,d) double w,h,d; /**/
{ ndc_width=w; if (vp_xmax>w) vp_xmax=w;
ndc_height=h; if (vp_ymax>h) vp_ymax=h;
ndc_depth=d;
}
/* new_frame - clear screen and redraw retained segments */
new_frame() {clear_graphics();} /**/
/* parallel - define direction for parallel projection */
parallel(x,y,z) double x,y,z; /**/
{ p1=x; p2=y; p3=left_handed*z; persp_proj=0;
need_depth=persp_proj||front_clipping||back_clipping;
}
/* perspective - define center of projection for perspective projection */
perspective(x,y,z) double x,y,z; /**/
{ p1=x; p2=y; p3=left_handed*z; persp_proj=1;
need_depth=persp_proj||front_clipping||back_clipping;
}
/* polyline - draw lines connecting a series of points */
polyline_abs_3(x,y,z,n) double *x,*y,*z; int n; /**/
{ move_abs_3(*x++,*y++,*z++); while(--n)line_abs_3(*x++,*y++,*z++);
}
polyline_abs_2(x,y,n) double *x,*y; int n; /**/
{ move_abs_2(*x++,*y++); while(--n)line_abs_2(*x++,*y++);
}
polyline_rel_3(x,y,z,n) double *x,*y,*z; int n; /**/
{
move_rel_3(*x++,*y++,*z++);
while(--n)line_abs_3(*x++, *y++, *z++);
}
polyline_rel_2(x,y,n) double *x,*y; int n; /**/
{
move_rel_2(*x++,*y++); while(--n)line_rel_2(*x++,*y++);
}
/* polygon - draw a polygon defined by its vertices */
polygon_abs_3(x,y,z,n) double *x,*y,*z; int n; /**/
{ double cx,cy,cz;
move_abs_3(*x++,*y++,*z++);
cx=cur_x; cy=cur_y; cz=cur_z;
while(--n)line_abs_3(*x++,*y++,*z++);
line_abs_3(cx,cy,cz);
}
polygon_abs_2(x,y,n) double *x,*y; int n; /**/
{ double cx,cy;
move_abs_2(*x++,*y++); cx=cur_x; cy=cur_y;
while(--n)line_abs_2(*x++,*y++);
line_abs_2(cx,cy);
}
polygon_rel_3(x,y,z,n) double *x,*y,*z; int n; /**/
{ double cx,cy,cz;
double sx,sy,sz;
cx=cur_x; cy=cur_y; cz=cur_z;
move_rel_3(*x++,*y++,*z++); sx=cur_x; sy=cur_y; sz=cur_z;
while(--n)line_abs_3(cx+ *x++,cy+ *y++,cz+ *z++);
line_abs_3(sx,sy,sz);
}
polygon_rel_2(x,y,n) double *x,*y; int n; /**/
{ double sx,sy;
move_rel_2(*x++,*y++); sx=cur_x; sy=cur_y;
while(--n)line_rel_2(*x++, *y++);
line_abs_2(sx,sy);
}
/* polymarker - draw markers at a series of points */
polymarker_abs_3(x,y,z,n) double *x,*y,*z; int n; /**/
{ while(n--)marker_abs_3(*x++,*y++,*z++);
}
polymarker_abs_2(x,y,n) double *x,*y; int n; /**/
{ while(n--)marker_abs_2(*x++,*y++);
}
polymarker_rel_3(x,y,z,n) double *x,*y,*z; int n; /**/
{ double cx,cy,cz;
cx=cur_x; cy=cur_y; cz=cur_z;
while(n--)marker_abs_3(cx+ *x++,cy+ *y++,cz+ *z++);
}
polymarker_rel_2(x,y,n) double *x,*y; int n; /**/
{ double cx,cy;
cx=cur_x; cy=cur_y;
while(n--)marker_abs_2(cx+ *x++,cy+ *y++);
}
/* select_view_surface - select the screen mode */
select_view_surface(mode) int mode; /**/
{ if(!initialized) init_graphics(mode);
initialized=1;
}
/* set character attributes */
set_charsize(cw,ch) double cw,ch; {} /**/
set_charplane(dx,dy,dz) double dx,dy,dz; {} /**/
set_charup_2(dx,dy) double dx,dy; {} /**/
set_charup_3(dx,dy,dz) double dx,dy,dz; {} /**/
set_charpath(i) int i; {} /**/
set_charspace(x) double x; {} /**/
set_charjust(i) int i; {} /**/
set_charprecision(i) int i; {} /**/
/* set_front_plane_clipping - enable depth clipping if i is nonzero */
set_front_plane_clipping(i) int i; /**/
{ front_clipping=i; need_depth=persp_proj||front_clipping||back_clipping;
}
/* set_back_plane_clipping - enable depth clipping if i is nonzero */
set_back_plane_clipping(i) int i; /**/
{ back_clipping=i; need_depth=persp_proj||front_clipping||back_clipping;
}
/* set line parameters */
set_linestyle(style) int style; /**/
{ if(style<0) style=0;
else if(style>MAX_STYLE) style=MAX_STYLE;
current_linestyle=style;
reset_line();
}
set_linewidth(w) int w; /**/
{ if(w<1) w=1;
else if(w>25) w=25;
#ifdef TEST
pen_diameter=4;/***************************************/
#endif
current_linewidth=w;
reset_line();
}
/* set_marker_symbol - set symbol for marker & polymarker */
set_marker_symbol(n) int n; /**/
{ if (n<1) n=1;
else {if (n>MAX_MARKER_SYMBOL) n=MAX_MARKER_SYMBOL;}
marker_symbol=n;
}
/* terminate_core - terminate graphics */
terminate_core() /**/
{if(initialized) finish_graphics();
initialized=0;
}
/* terminate_view_surface - terminate the screen mode */
terminate_view_surface() /**/
{if(initialized) finish_graphics();
initialized=0;
}
/* text - display text string */
text(s) char *s; /**/
{ char *t;
t=s;
while(*t && isspace(*t)) t++;
if(*t==0) return;
if(front_clipping) {if(nn<=wmin) return;}
if(back_clipping) {if(nn>wmax) return;}
if(persp_proj)
{if(nn<=0.) return;
current_x=(int)(uu/nn); current_y=(int)(vv/nn);
}
if(clipping)
{if((current_x<wmin1)||(current_x>wmax1)||
(current_y<wmin2)||(current_y>wmax2) ) return;
}
gotoxy(current_x,current_y);
(*draw_text)(s);
#ifdef DEBUG
if(current_y<textymin) textymin=current_y;
if(current_y>textymax) textymax=current_y;
#endif
}
/* viewport - define the area on the display to be used */
viewport3(xmin,xmax,ymin,ymax,zmin,zmax) /**/
double xmin,xmax,ymin,ymax,zmin,zmax;
{ vp_xmin=xmin; vp_ymin=ymin; vp_zmin=zmin;
vp_xmax=xmax; vp_ymax=ymax; vp_zmax=zmax;
}
/* set_view_depth - set distances for depth clipping */
set_view_depth(front_distance,back_distance) /**/
double front_distance,back_distance;
{ wmin=front_distance; wmax=back_distance;
}
/* view_plane_distance - set distance from vrp to view plane */
view_plane_distance(v) double v; {vdist=v;} /**/
/* view_plane_normal - define normal to view plane */
view_plane_normal(dx,dy,dz) double dx,dy,dz; /**/
{norm1=dx; norm2=dy; norm3=left_handed*dz;
}
/* view_reference_point - define view reference point */
view_reference_point(x,y,z) double x,y,z; {vrp1=x; vrp2=y; vrp3=z;} /**/
/* view_up - define world direction which should appear "up" in view */
view_up_2(dx,dy) double dx,dy; {view_up_3(dx,dy,0.);} /**/
view_up_3(dx,dy,dz) double dx,dy,dz; /**/
{up1=dx; up2=dy; up3=left_handed*dz;}
/* window - define the values of (rotated) world coordinates in the view */
window(xmin,xmax,ymin,ymax) double xmin,xmax,ymin,ymax; /**/
{ umin=xmin; umax=xmax; vmin=ymin; vmax=ymax;
}
/*--------------------------------------------------------------------------
support functions
*/
/* clip - 3D clipping
returns nonzero if entire line is invisible
line is from a to b
clipping requirement is x DOT c > c[3], where dot
product runs over first three elements */
static int clip(double *a,double *b,double *c)
{ register double *fp, q, qp;
double ac,bc;
ac=a[0]*c[0] + a[1]*c[1] + a[2]*c[2];
bc=b[0]*c[0] + b[1]*c[1] + b[2]*c[2];
if(ac>bc){fp=a; a=b; b=fp; q=ac; ac=bc; bc=q; } /* ensure b "most visible" */
if(ac>=c[3]) return 0; /* both points visible */
if(bc<=c[3]) return 1; /* both points invisible */
/* Now we know a DOT c < c[3] < b DOT c ,
and we need a new a such that a DOT c = c[3] .
We use q*a + (1-q)*b, where
q = (c[3] - b DOT c)/((a - b) DOT c) */
q=(c[3]-bc)/(ac-bc); /* note ac < c[3] < bc, so denominator nonzero */
qp=1.-q;
a[0]=q*a[0] + qp*b[0]; a[1]=q*a[1] + qp*b[1]; a[2]=q*a[2] + qp*b[2];
return 0; /* both points are now visible */
}
/*--------------------------------------------------------------------------
Interface routines between CORE graphics routines
and integer or "device coordinate" based routines
*/
/* icline - draw line from cp to new position with clipping */
icline(a1,a2,b1,b2) /**/
int a1,a2,b1,b2; /* beginning and end points of line */
{ int t; /* temporary for exchanges */
reversed=0;
/* ensure a1<=b1 */
if(a1>b1) {t=a1; a1=b1; b1=t; t=a2; a2=b2; b2=t; reversed=1;}
if(a1<wmin1)
{if(b1<wmin1)return; /* both points left of window */
a2=((wmin1-b1)*(long)a2+(a1-wmin1)*(long)b2)/(a1-b1); a1=wmin1; /* find point on edge */
}
if(b1>wmax1)
{if(a1>wmax1)return; /* both points right of window */
b2=((wmax1-a1)*(long)b2+(b1-wmax1)*(long)a2)/(b1-a1); b1=wmax1; /* find point on edge */
}
/* ensure a2<=b2 */
if(a2>b2) {t=a2; a2=b2; b2=t; t=a1; a1=b1; b1=t; reversed ^=1;}
if(a2<wmin2)
{if(b2<wmin2)return; /* both points below window */
a1=((wmin2-b2)*(long)a1+(a2-wmin2)*(long)b1)/(a2-b2); a2=wmin2; /* find point on edge */
}
if(b2>wmax2)
{if(a2>wmax2)return; /* both points above window */
b1=((wmax2-a2)*(long)b1+(b2-wmax2)*(long)a1)/(b2-a2); b2=wmax2; /* find point on edge */
}
(*after_clip)(a1,a2,b1,b2);
}
#ifdef erasing
/* icerase - erase line from cp to new position with clipping */
icerase(a1,a2,b1,b2) /**/
int a1,a2,b1,b2; /* beginning and end points of line */
{ t; /* temporary for exchanges */
reversed=0;
/* ensure a1<=b1 */
if(a1>b1) {t=a1; a1=b1; b1=t; t=a2; a2=b2; b2=t; reversed=1;}
if(a1<wmin1)
{if(b1<wmin1)return; /* both points left of window */
a2=((wmin1-b1)*(long)a2+(a1-wmin1)*(long)b2)/(a1-b1); a1=wmin1; /* find point on edge */
}
if(b1>wmax1)
{if(a1>wmax1)return; /* both points right of window */
b2=((wmax1-a1)*(long)b2+(b1-wmax1)*(long)a2)/(b1-a1); b1=wmax1; /* find point on edge */
}
/* ensure a2<=b2 */
if(a2>b2) {t=a2; a2=b2; b2=t; t=a1; a1=b1; b1=t; reversed ^=1;}
if(a2<wmin2)
{if(b2<wmin2)return; /* both points below window */
a1=((wmin2-b2)*(long)a1+(a2-wmin2)*(long)b1)/(a2-b2); a2=wmin2; /* find point on edge */
}
if(b2>wmax2)
{if(a2>wmax2)return; /* both points above window */
b1=((wmax2-a2)*(long)b1+(b2-wmax2)*(long)a1)/(b2-a2); b2=wmax2; /* find point on edge */
}
(*erase_line)(a1,a2,b1,b2);
}
/* ierase - erase line to new location */
ierase(x2,y2) int x2,y2; /**/
{ (*erase_line)(current_x,current_y,x2,y2);
current_x=x2; current_y=y2;
}
#endif
/* iwline - draw a wide line from (x1,y1) to (x2,y2) */
iwline(x1,y1,x2,y2) int x1,y1,x2,y2; /**/
{ static int dx, dy, adx, ady, sx, sy, ty, s, c, xe, ye;
static int lgh, dl;
dx=x2-x1; dy=y2-y1;
adx=abs(dx); ady=abs(dy*aspect);
/* lgh is approximately sqrt(dx**2 + (dy*aspect/10)**2)
Note ordering of calculations to avoid overflow. */
/*
This still overflows if dx = dy > 1310, so we cannot
allow pixels_wide or pixels_high > 1310.
Also fails for dx=0, dy=1, and aspect<10 (i.e. pixels
that are wider than they are high).
*/
if(10*adx<ady) lgh=(ady/2 + 25*adx/ady*adx/6*5)/5;
else
{if(adx==0) return;
/*
This fails for dy = dx > 19660
*/
lgh = (adx*10 + (ady/24)*(ady/adx))/10;
}
/* (sx,sy) is orthogonal to (dx,dy) */
dl=lgh>>1;
if(dy>0)
sx=((aspect*dy/10*aspect/10*current_linewidth+dl)/lgh)*pen_diameter;
else
sx=((aspect*dy/10*aspect/10*current_linewidth-dl)/lgh)*pen_diameter;
if(dx>0) ty=sy= -((current_linewidth*dx+dl)/lgh)*pen_diameter;
else ty=sy= -((current_linewidth*dx-dl)/lgh)*pen_diameter;
if(sx<0) {sx= -sx; ty=sy= -sy;}
/* sx>=0, so shifting is OK. sy may be negative, so use division */
x1-=sx>>1; xe=x2-=sx>>1; y1-=sy/2; ye=y2-=sy/2;
if(sy<0) {dy= -pen_diameter; sy= -sy;}
else {dy= pen_diameter;}
s=sx+sy;
c=(sx-sy)/2;
if(pen_diameter!=1)
{s /= pen_diameter;
(*after_wide)(x1+(sx*(current_linewidth-1))/current_linewidth,
y1+(ty*(current_linewidth-1))/current_linewidth ,x1, y1);
}
while(s--)
{(*after_wide)(x1, y1, x2, y2);
if(c<0) {c+=sx; y1+=dy; y2+=dy;}
else {c-=sy; x1+=pen_diameter; x2+=pen_diameter;}
}
if(pen_diameter!=1)
(*after_wide)(xe, ye,
xe+(sx*(current_linewidth-1))/current_linewidth,
ye+(ty*(current_linewidth-1))/current_linewidth);
}
/* idline - draw dashed line from (x1,y1) to (x2,y2) */
idline(x1,y1,x2,y2) int x1,y1,x2,y2; /**/
{ int x,y,mx,my,xa,ya,t;
int dx,dy,adx,ady,dist;
long remain;
if(reversed) {t=x1; x1=x2; x2=t; t=y1; y1=y2; y2=t; reversed=0;}
if(using_dash_hardware)
{(*after_dashed)(x1,y1,x2,y2);
return;
}
dx=(x2-x1); dy=(y2-y1);
adx=abs(dx); ady=abs(dy*aspect);
/* using the approximation
sqrt(x**2 + y**2) approximately x + (5*x*x)/(12*y)
when x > y */
/* note ordering of calculations to avoid overflow */
if(10*adx<ady) dist=(ady/2 + 25*adx/ady*adx/6*5)/5;
else
{if(adx==0)return;
dist=(adx*10 + (ady/24)*(ady/adx))/10;
}
remain=dist; xa=x1; ya=y1;
while(remain>step)
{remain-=step;
if(style_index&1)
{(*after_dashed)(xa,ya,(int)(x2-(remain*dx)/dist),
(int)(y2-(remain*dy)/dist));
}
else {xa=x2-(remain*dx)/dist; ya=y2-(remain*dy)/dist;}
if(++style_index>=DASHES) style_index=0;
step=style_array[style_index];
}
if(style_index&1)(*after_dashed)(xa,ya,x2,y2);
step-=remain;
}
/* reset_line() - set up the three pointers to integer line routines */
reset_line() /**/
{ int i,j, using_width_hardware=0;
/*
legal sequences...
line (icline) (idline) draw_line
line (idline) iwline (icline) draw_line
...because clipping must follow widening and widening must follow dashes.
Hardware linestyles and wide lines may be used as follows...
available requested used
wide style wide style wide style
0 0 x x 0 0 don't use what isn't there
0 1 x 0 0 0 don't use what isn't requested
0 1 0 1 0 1
0 1 1 1 0 0 on multiple passes, dashes don't match
1 0 0 x 0 0 don't use what isn't requested
1 0 1 0 1 0
1 0 1 1 0 0 since pen may not be round
1 1 A B A B
*/
if(!initialized) init_graphics(0); /* note correct mode is unknown */
initialized=1;
if(new_linewidth)
{if(current_linewidth==1 || current_linestyle==SOLID || new_linestyle)
{(*new_linewidth)(current_linewidth);
using_width_hardware=1;
}
else (*new_linewidth)(1);
}
if(new_linestyle)
{if(current_linewidth==1 || current_linestyle==SOLID || new_linewidth)
(*new_linestyle)(current_linestyle);
else
(*new_linestyle)(SOLID);
}
if((current_linewidth<=1) || using_width_hardware)
{after_wide=after_dashed=draw_line;
after_clip= (current_linestyle!=SOLID) ? idline : after_dashed;
after_line= clipping ? icline : after_clip;
using_dash_hardware = (new_linestyle != NULL);
}
else
{after_clip=draw_line;
after_wide= clipping ? icline : after_clip;
after_dashed= ((current_linewidth>1) && !using_width_hardware)
? iwline : after_wide;
after_line= (current_linestyle!=SOLID) ? idline : after_dashed;
using_dash_hardware=0;
}
/* printf("line routine locations...\n");
printf("after_line=%x \n",after_line);
printf("idline=%x after_dashed=%x \n",idline,after_dashed);
printf("iwline=%x after_wide=%x \n",iwline,after_wide);
printf("icline=%x after_clip=%x \n",icline,after_clip);
printf("draw_line=%x \n",draw_line);
*/
aspect=10*best_height*pixels_wide/(best_width*pixels_high);
if(aspect < 10) aspect = 10; /* prevents iwline and idline problems */
j=(current_linestyle-1)*DASHES;
for(i=0; i<DASHES; i++, j++)
{if(styles[j])
style_array[i]=
(styles[j]+current_linewidth)*pen_diameter*aspect/10;
else style_array[i]=0;
}
step=style_array[0];
style_index=1;
}
/* initialize_view_surface - initialize the screen */
initialize_view_surface(mode) int mode; /**/
{ int i,j;
double t,xx,yy;
if(!initialized) init_graphics(mode);
initialized=1;
if(!scaled)
/*
A rectangle with width = pixels_wide/best_width
and height = pixels_high/best_height
would be a square
*/
{t=sqrt(pixels_wide/best_width/pixels_high*best_height);
xx=.1*t*pen_diameter;
yy=.2/t*pen_diameter;
j=mark_index[MAX_MARKER_SYMBOL]*4;
for (i=0 ; i<j ; i+=2)
{xm[i]*=xx; xm[i+1]*=yy;
}
scaled=1;
}
}